package com.example.finalproject.experiments.camera

import android.Manifest
import android.app.Activity
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.ImageFormat
import android.hardware.camera2.*
import android.media.ImageReader
import android.os.*
import android.util.Log
import android.view.Surface
import android.view.SurfaceHolder
import android.view.SurfaceView
import android.widget.Button
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import com.example.finalproject.R
import java.io.File
import java.io.FileOutputStream
import java.text.SimpleDateFormat
import java.util.*

class CameraPreviewActivity : AppCompatActivity() {
    private lateinit var surfaceView: SurfaceView
    private lateinit var btnCapture: Button
    private lateinit var cameraManager: CameraManager
    private var cameraDevice: CameraDevice? = null
    private var captureSession: CameraCaptureSession? = null
    private var imageReader: ImageReader? = null
    private var photoFile: File? = null
    private var photoTime: String = ""
    private val handlerThread = HandlerThread("CameraThread")
    private lateinit var handler: Handler

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_camera_experiment)
        surfaceView = findViewById(R.id.surfaceView)
        btnCapture = findViewById(R.id.btnCapture)
        handlerThread.start()
        handler = Handler(handlerThread.looper)
        cameraManager = getSystemService(CAMERA_SERVICE) as CameraManager
        surfaceView.holder.addCallback(object : SurfaceHolder.Callback {
            override fun surfaceCreated(holder: SurfaceHolder) {
                openCamera()
            }
            override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {}
            override fun surfaceDestroyed(holder: SurfaceHolder) {
                closeCamera()
            }
        })
        btnCapture.setOnClickListener {
            takePicture()
        }
    }

    private fun openCamera() {
        try {
            val cameraId = cameraManager.cameraIdList[0]
            if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.CAMERA), 1)
                return
            }
            val characteristics = cameraManager.getCameraCharacteristics(cameraId)
            val map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)
            val previewSize = map!!.getOutputSizes(SurfaceHolder::class.java)[0]
            imageReader = ImageReader.newInstance(previewSize.width, previewSize.height, ImageFormat.JPEG, 1)
            imageReader?.setOnImageAvailableListener({ reader ->
                val image = reader.acquireNextImage()
                val buffer = image.planes[0].buffer
                val bytes = ByteArray(buffer.remaining())
                buffer.get(bytes)
                image.close()
                photoFile?.let {
                    FileOutputStream(it).use { output ->
                        output.write(bytes)
                    }
                    val intent = Intent()
                    intent.putExtra("photo_path", it.absolutePath)
                    intent.putExtra("photo_time", photoTime)
                    setResult(Activity.RESULT_OK, intent)
                    finish()
                }
            }, handler)
            cameraManager.openCamera(cameraId, object : CameraDevice.StateCallback() {
                override fun onOpened(camera: CameraDevice) {
                    cameraDevice = camera
                    startPreview()
                }
                override fun onDisconnected(camera: CameraDevice) { camera.close() }
                override fun onError(camera: CameraDevice, error: Int) { camera.close() }
            }, handler)
        } catch (e: Exception) {
            Toast.makeText(this, "打开相机失败", Toast.LENGTH_SHORT).show()
        }
    }

    private fun startPreview() {
        try {
            val surface = surfaceView.holder.surface
            val previewRequestBuilder = cameraDevice!!.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)
            previewRequestBuilder.addTarget(surface)
            cameraDevice!!.createCaptureSession(listOf(surface, imageReader!!.surface), object : CameraCaptureSession.StateCallback() {
                override fun onConfigured(session: CameraCaptureSession) {
                    captureSession = session
                    previewRequestBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO)
                    session.setRepeatingRequest(previewRequestBuilder.build(), null, handler)
                }
                override fun onConfigureFailed(session: CameraCaptureSession) {
                    Toast.makeText(this@CameraPreviewActivity, "预览失败", Toast.LENGTH_SHORT).show()
                }
            }, handler)
        } catch (e: Exception) {
            Toast.makeText(this, "开始预览失败", Toast.LENGTH_SHORT).show()
        }
    }

    private fun takePicture() {
        try {
            val timeStamp = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).format(Date())
            photoTime = timeStamp
            val fileName = "IMG_${System.currentTimeMillis()}.jpg"
            photoFile = File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), fileName)
            val captureBuilder = cameraDevice!!.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE)
            captureBuilder.addTarget(imageReader!!.surface)
            captureBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO)
            captureSession?.capture(captureBuilder.build(), null, handler)
            Log.d("CameraPreviewActivity", "Photo file path: " + photoFile!!.absolutePath)
        } catch (e: Exception) {
            Toast.makeText(this, "拍照失败", Toast.LENGTH_SHORT).show()
        }
    }

    private fun closeCamera() {
        captureSession?.close()
        cameraDevice?.close()
        imageReader?.close()
        handlerThread.quitSafely()
    }

    override fun onDestroy() {
        super.onDestroy()
        closeCamera()
    }
}